///******************** NG.Respate(C)  **********************************
//* 产品名称: Respate 科技
//* 文件名称: signal.c
//* 程序作者: 雷帕特公司(南宫子萍)
//* 程序版本: V1.1														   
//* 编制日期: 2019/1/29
//* 功能描述: tftp服务器
//* QQ:	2085827949
//**********************************************************************/
#include "lap_tftp.h"
#include "LapSocket.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <stdlib.h>

#include "laperro.h"	// 系统日志 && DBUG 调试
#include <sys/epoll.h>
#include <netdb.h>
/*********************************************************************************
** 函数名称: tftp_get
** 功能描述: 从服务器获取文件
** 输入参数: name: 文件名          
** 输出参数: None.
** 返回参数: return response .
**********************************************************************************/
int tftp_severRx(const char* name)
{
    
}



/*********************************************************************************
** 函数名称: tftp_put
** 功能描述: 上传文件到服务器
** 输入参数: name: 文件名        
** 输出参数: None.
** 返回参数: return response .
**********************************************************************************/
int tftp_severTx(char* name)
{

}

FILE* file_log = NULL;	// 系统日志
#define MAXEPOLLSIZE 100

extern int Lap_addEpollEvent(int efd,int fd,int events);

// 等待客户端连接
int tftp_waitClient(int efd,int lfd)
{

	struct sockaddr_in c_addr;  // 客户端
    tftpPackage pack;
    int clen = sizeof(struct sockaddr_in);

    char buff[1024] = {0};
    int len = recvfrom(lfd,buff,sizeof(buff),0,&c_addr,&clen);
    tftp_Stream2Pack(&pack,buff,len);


    // 读写操作
    if(pack.prw.opcode == TFTP_RRQ || pack.prw.opcode == TFTP_WRQ)
    {
        char clientIP[18]={0};     // 客户端IP
        char ClientPort[10]={0};   // 客户端Port
        
        // 连接
        int c_fd = Lap_UDP_Connect(tConfig.port,NULL,&c_addr);
        if(c_fd < 0) { Lap_sysLog(file_log,"Lap_UDP_Connect Err"); return -1;}

        if(Lap_addEpollEvent(efd,c_fd,EPOLLIN | EPOLLET) < 0) 
        {
             Lap_sysLog(file_log,"Lap_UDP_Connect Err"); 
             close(c_fd);
             return -1;
        }

         // 获取客户端信息
        getnameinfo((struct sockaddr *)&c_addr, sizeof(struct sockaddr), clientIP, sizeof(clientIP), \
            ClientPort, sizeof(ClientPort), NI_NUMERICHOST | NI_NUMERICSERV);

        Lap_sysLog(file_log,"Client connected IP:%s port:%s Requst %s %s",clientIP,ClientPort,\
            (pack.prw.opcode==TFTP_RRQ? "Get":"Put"),pack.prw.name);

        write(lfd,buff,len);   // 将接收到的数据写回cfd中
        // sendto();
        return 0;
    }
    else    // 返回错误信息
    {
        char errMsg[]="Illegal TFTP operation.";
        pack.perr.opcode = TFTP_ERROR;
        pack.perr.errcode = TFTP_ERR_OP_ILLEGAL;
        pack.perr.errmsg = errMsg;
        memset(buff,0,sizeof(buff));
        len = tftp_Pack2Stream(&pack,buff,sizeof(errMsg));
        sendto(lfd,buff,len,0,&c_addr,sizeof(struct sockaddr_in));
        Lap_sysLog(file_log,"clilent Illegal TFTP operation.");
    }
}

// 打开的文件描述符
int fd_buff[MAXEPOLLSIZE]={0};

struct 
{
    int fd;     // 打开的文件描述符
    int mode;   // 请求模式
}tftpRequstInfo;

// 客户端事件回调函数
int tftp_clientHandler(int efd,int cfd)
{
    tftpPackage pack;
    char buff[1024] = {0};
    int len = read(cfd,buff,sizeof(buff));
    tftp_Stream2Pack(&pack,buff,len);
    printf("aaa\r\n");
    // 错误判断
    // if(pack.pack.opcode !=TFTP_ACK && )

    switch(pack.pack.opcode)
    {
        case TFTP_RRQ:  // 请求读数据
        // int fd = open(pack.prw.name,O_RDONLY);
        break;

        case TFTP_WRQ:  // 请求写数据
        break;

        case TFTP_ACK:  // 应答
        break;

        default:        // 其它:错误
        break;
    }
    write(cfd,buff,len);
    return 0;
}




int Lap_epollEvents(int fd)
{
    // 1.创建epoll监听事件
    struct epoll_event ev;
    struct epoll_event events[MAXEPOLLSIZE];
    
    int efd = epoll_create(MAXEPOLLSIZE);   // 创建epoll树
    LAP_NegErrLog(file_log,efd,"epoll_create err");
    if(efd < 0) goto err1;

    ev.events = EPOLLIN | EPOLLET;       // 监听读事件,边缘触发
    ev.data.fd = fd;
    if(epoll_ctl(efd,EPOLL_CTL_ADD,fd,&ev) != 0) goto err2;

    // 2.epoll 事件处理
    while(1)
    {
        // 等待事件到来
        int nfds = epoll_wait(efd,events,MAXEPOLLSIZE,-1);
        for(int i=0; i < nfds; i++)
        {
            // 有新客户端连接
            if(events[i].data.fd == fd) tftp_waitClient(efd,fd);
            else tftp_clientHandler(efd,events[i].data.fd);
        }
    }

err2:
    LAP_NegErrLog(file_log,efd,"epoll_ctl efd err");
    close(efd);

err1:
    return -1;
}

int Lap_epollCreate()
{
	int ret = -1;

	tftpConfig config =
	{	
		.port = 8089,
		.block = 512,
		.ip = "123.123.123.128",
		.mode = TFTP_MODE_NETAS,
		.download = "./bin_dir"
	};

	//tftp_printfConfig(&tConfig);
	tftp_config(&config);
	struct sockaddr_in s_addr;	// 服务器 网络属性

	// file_log = Lap_openLog("./bin_dir/lap.log");	// 初始化 系统日志
    file_log = stdout;
	LAP_NegErrLog(file_log,-1,"log 日志系统启动！");

	int s_fd = Lap_UDP_Socket4(config.port,config.ip,&s_addr);	// 创建套接字
	LAP_NegErrLog(file_log,s_fd,"创建套接字错误！");
	if(s_fd < 0) goto err;

	ret = Lap_Bind(s_fd,SOL_SOCKET,&s_addr);	// 绑定服务器端口和IP
	LAP_NegErrLog(file_log,ret,"绑定错误！");
	if(ret < 0)	goto err;

    printf("Lap_epollEvents ing....\r\n");
    // epoll 事件处理函数
    Lap_epollEvents(s_fd);

err:
	LAP_NegErrLog(file_log,-1,"log 日志系统退出中ing.......");
	close(s_fd);
	Lap_closeLog(file_log);
}

#include "libnet.h"
int main()
{
    
    Lap_epollCreate();
    return 0;
}